/*
 * Copyright (C) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "file_type_util.h"
#include "log.h"

namespace ImageKnifePro {

std::map<ImageFormat, std::vector<std::vector<uint8_t>>>& FileTypeUtil::GetFileSignatureMap()
{
    // 文件签名映射表，key为 ImageFormat 枚举
    static std::map<ImageFormat, std::vector<std::vector<uint8_t>>> fileSignatureMap_ = {
        {ImageFormat::JPG, {{0xFF, 0xD8}}}, // JPEG
        {ImageFormat::BMP, {{0x42, 0x4D}}}, // BMP
        {ImageFormat::WEBP, {{0x52, 0x49, 0x46, 0x46}}}, // WebP
        {ImageFormat::PNG, {{0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}}}, // PNG
        {ImageFormat::GIF, {{0x47, 0x49, 0x46, 0x38, 0x39, 0x61}, {0x47, 0x49, 0x46, 0x38}}}, // GIF
        {ImageFormat::SVG, {{0x3C, 0x3F, 0x78, 0x6D, 0x6C}, {0x3C, 0x73, 0x76, 0x67, 0x20}}}, // SVG
        {ImageFormat::TIFF, {{0x49, 0x20, 0x49}, {0x49, 0x49, 0x2A, 0x00},
            {0x4D, 0x4D, 0x00, 0x2A}, {0x4D, 0x4D, 0x00, 0x2B}}}, // TIFF
        {ImageFormat::HEIC, {{0x00, 0x00, 0x00, 0x18, 0x66, 0x74, 0x79, 0x70, 0x68, 0x65, 0x69, 0x63},
            {0x00, 0x00, 0x00, 0x1C, 0x66, 0x74, 0x79, 0x70, 0x6D, 0x69, 0x66, 0x31}}}, // HEIC
        {ImageFormat::ICO, {{0x00, 0x00, 0x01, 0x00}}} // ICO 文件签名
    };
    return fileSignatureMap_;
}

std::string FileTypeUtil::ImageFormatToString(ImageFormat imageFormat)
{
    static std::unordered_map<ImageFormat, std::string> formatMap = {
        {ImageFormat::JPG, "jpg"},
        {ImageFormat::PNG, "png"},
        {ImageFormat::WEBP, "webp"},
        {ImageFormat::BMP, "bmp"},
        {ImageFormat::GIF, "gif"},
        {ImageFormat::SVG, "svg"},
        {ImageFormat::TIFF, "tiff"},
        {ImageFormat::HEIC, "heic"},
        {ImageFormat::ICO, "ico"},
        {ImageFormat::UNKNOWN, ""}
    };
    if (formatMap.find(imageFormat) != formatMap.end()) {
        return formatMap[imageFormat];
    }
    return std::string();
}

ImageFormat FileTypeUtil::StringToImageFormat(std::string formatInfo)
{
    static std::unordered_map<std::string, ImageFormat> formatMap = {
        {"jpg", ImageFormat::JPG},
        {"png", ImageFormat::PNG},
        {"webp", ImageFormat::WEBP},
        {"bmp", ImageFormat::BMP},
        {"gif", ImageFormat::GIF},
        {"svg", ImageFormat::SVG},
        {"tiff", ImageFormat::TIFF},
        {"heic", ImageFormat::HEIC},
        {"ico", ImageFormat::ICO}
    };
    if (formatMap.find(formatInfo) != formatMap.end()) {
        return formatMap[formatInfo];
    }
    return ImageFormat::UNKNOWN;
}

ImageFormat FileTypeUtil::CheckImageFormat(const uint8_t* data, size_t length)
{
    const int expectedFilelength = 32;
    if (length < expectedFilelength) {
        IMAGE_KNIFE_LOG(LOG_ERROR, "File length less than expect length");
        return ImageFormat::UNKNOWN;
    }
    return GetFileType(data, length);
}

ImageFormat FileTypeUtil::GetFileType(const uint8_t* data, size_t length)
{
    for (const auto& entry : GetFileSignatureMap()) {
        const ImageFormat fileType = entry.first;
        const std::vector<std::vector<uint8_t>>& signatures = entry.second;

        for (const auto& signature : signatures) {
            if (MatchesSignature(data, length, signature, fileType)) {
                return fileType;
            }
        }
    }

    return ImageFormat::UNKNOWN; // 无法匹配的情况
}

bool FileTypeUtil::MatchesSignature(const uint8_t* data, size_t length, const std::vector<uint8_t>& signature,
                                    ImageFormat fileType)
{
    if (length < signature.size()) {
        return false; // 文件长度不足，无法匹配魔数
    }

    size_t offset = (fileType == ImageFormat::HEIC) ? 4 : 0;

    for (size_t i = offset; i < signature.size(); ++i) {
        if (data[i] != signature[i]) {
            return false; // 魔数不匹配
        }
    }
    return true; // 文件头部魔数匹配
}
}
